﻿using System;
using System.Collections.Generic;
using _5E.Infrastructure.Domain;
using _5E.Infrastructure.Querying;
using _5E.Infrastructure.UnitOfWork;
using NHibernate;
using NHibernate.Criterion;

namespace _5E.NHibernateRepository.Repository
{
    public abstract class RepositoryBase<T, TId> : IRepository<T, TId>
        where T : class,IAggregateRoot
    {
        private IUnitOfWork m_unitOfWork = null;

        public RepositoryBase(IUnitOfWork unitOfWork)
        {
            m_unitOfWork = unitOfWork;
        }

        public void Add(T entity)
        {
            SessionFactory.CurrentSession.Save(entity);
        }

        public void Remove(T entity)
        {
            SessionFactory.CurrentSession.Delete(entity);
        }

        public void Save(T entity)
        {
            SessionFactory.CurrentSession.Merge(entity);
        }

        public T FindBy(TId id)
        {
            return SessionFactory.CurrentSession.Get<T>(id);
        }

        public IEnumerable<T> FindAll()
        {
            ICriteria criteria = SessionFactory.CurrentSession.CreateCriteria(typeof(T));
            return criteria.List<T>();
        }

        public IEnumerable<T> FindAll(Int32 pageIndex, Int32 pageSize)
        {
            ICriteria criteria = SessionFactory.CurrentSession.CreateCriteria(typeof(T));
            if (pageIndex < 1)
                pageIndex = 1;
            return criteria.SetFirstResult((pageIndex - 1) * pageSize).SetMaxResults(pageSize).List<T>();
        }

        public IEnumerable<T> FindBy(Query query)
        {
            ICriteria criteria = SessionFactory.CurrentSession.CreateCriteria(typeof(T));

            AppendCriteria(criteria);

            query.TranslateToNHibernateQuery<T>(criteria);

            return criteria.List<T>();
        }

        public IEnumerable<T> FindBy(Query query, Int32 pageIndex, Int32 pageSize)
        {
            ICriteria criteria = SessionFactory.CurrentSession.CreateCriteria(typeof(T));

            AppendCriteria(criteria);

            query.TranslateToNHibernateQuery<T>(criteria);

            if (pageIndex < 1)
                pageIndex = 1;
            return criteria.SetFirstResult((pageIndex - 1) * pageSize).SetMaxResults(pageSize).List<T>();
        }

        public Int32 RowCount(Query query)
        {
            ICriteria criteria = SessionFactory.CurrentSession.CreateCriteria(typeof(T));

            AppendCriteria(criteria);

            query.TranslateToNHibernateQuery<T>(criteria);
            return criteria.SetProjection(Projections.RowCount()).List<Int32>()[0];
        }

        public virtual void AppendCriteria(ICriteria criteria)
        {

        }
    }
}
